AppleScripting
AppleScript is a scripting language. Scripting languages have all the capabilities of other programming languages, but are easier to use because their structure is closer to everyday English.

AppleScripts can store data for later use and examine their surroundings to determine what to do next. They can also loop through certain instructions, repeating them as many times as you like, or until something specific happens. These features, and others, are what makes a scripting language - particularly AppleScript ideal for anyone that wants to automate a task.

AppleScript is different from other scripting languages because its reach isn't limited to a single application. AppleScript is part of the Macintosh operating system, and that enables it to work with several different applications at once if necessary. You can extract data from one application and hand it to another for processing with AppleScript, and it can even be used to control other Macs over the network.

Introduction
Support for AppleScript in Snak was introduced with version 4.5 and the support will continue to be expanded. In its current form the support is more than adequate to perform useful tasks and write substantial scripts. It is not yet extensive enough to support large script packages like HipScript and others, but that shortcoming will be remedied in future versions.

You can write simple command aliases in AppleScript, but the real power comes when you use "event handlers". These are snippets of AppleScript that you write and load into Snak. Snak will then call your event handlers when particular events happen, like someone joining a channel, leaving a channel, saying something, sending you a private message and more. The event handlers lets you truly customize the way Snak works and responds to events.

There are many good books about AppleScript, and I can in particular recommend "The TAO of AppleScript" by Derrick Schneider and "AppleScript Language Guide" from Apple that you can order from the print on demand service at http://www.fatbrain.com

In order to write an AppleScript that uses Snak, you need to open the Script Editor application that was installed as part of your operating system. In recent system versions it will be in the folder "Apple Extras:AppleScript"

A key idea in AppleScript is that every scriptable application contains a dictionary of the commands and elements it knows about. To see the Snak dictionary, run the Script Editor and select "Open Dictionary" under the file menu and select the Snak application:

Under the heading "Snak Suite" you see all the commands you can send to Snak - 
connect/disconnect/echo/do/type/select/match
and all the internal elements of the application that you can access through an AppleScript - 
channels, connections, users, ignoreitems ... and many more.

Your first script
First, launch the Script Editor application. This is where you will write the text of the script.

This is an example of a simple, yet (somewhat) useful little script. Once it is loaded into snak you will be able to type "/countops" and have the script execute and tell you the ratio of channel operators to normal users. The script asks Snak how many users are in the current channel, and how many ops there are among them. Then it calculates the ratio and displays a message.

Type the following text and save the file into the Scripts folder that is in the Snak folder. Save it under the filename "countops" (no spaces).  Don't worry that you might not understand all of it. The rest of this chapter will attempt to explain what is going on.

on run

tell application "Snak 4.6"

set n to numberofusers of channel currentchannel of connection currentconnection

set ops to count (get (every user whose op = true) of channel currentchannel of connection currentconnection)

set percent to ops / n * 100 as text

set percent to (round (percent + 0.5))

set commandstring to "/me sees " & ops & " gods and " & n - ops & " mortals on " & currentchannel & ". " & percent & "% of the people in " & currentchannel & " are gods."

do commandstring

end tell
end run

There are five main parts to AppleScript:

Objects - which points to items and information inside the application
Commands - which acts on those items and information
Variables - which allows you to store data for later use
Conditionals - which enable your script to make decisions based on a set of conditions
Repeat loops - which give you the capability to execute commands repeatedly

The above script shows examples of objects, commands, conditionals and variables. Starting with the first line "on run" this is a line that tells Snak in what situation to run the snippet, namely when the uses types "/countops". Other situations are explained later when event handlers are introduced.

The "tell application "Snak 4.6"" line is used by the AppleScript system itself and is used to set the target for the following block of AppleScript. Notice how the Script Editor automatically indents the following block.

Now we get to the  core of the little script, the place where the interesting action takes place. The next line uses both objects and a variable.

"set n to numberofusers of channel currentchannel of connection currentconnection" 

Here we ask Snak a complex question - how many users are there in the current channel on the current connection, and we store the result into a variable called "n". The channel and the connection are examples of objects.

A central concept in understanding AppleScript is that most scriptable applications have an "object hierarchy" meaning that objects are nested inside each other. You ask the top object (the application) for an object (the connection) that contains your ultimate goal (the channel), and then you ask that channel object for specific information like the number of users. 

The "tell application "Snak 4.6"" line you saw first points out the top object (the application) and the "set n to ..." line will first ask for the connection from the application, and then ask for the channel from the connection, and then it asks the channel for the number of users. Try and read the line from the right and you will see the sequence.

Trust me, once you understand the idea it really makes sense :-)

Snaks object hierarchy is:
The application contains connections (and more)
A connection contains channels (and more)
A channel contains users (and more)

The following line is quite complex. 

"set ops to count (get (every user whose op = true) of channel currentchannel of connection currentconnection)"

Like the previous one it uses a variable and objects, but it also introduces a conditional operation. Again we find a channel object but this time we ask it for a list of all users in the channel whose "op" status is true, meaning that they are channel operators. Then we take the number of results and store in a variable.

The "whose" conditional allows you to easily gather a collection of objects that satisfy a condition.

The next few lines perform the ratio calculation, and put together the string of text that Snak should display with the result.

"set commandstring to "/me sees .."

This line looks difficult, but all it does is to pull together the information we've already found, and fill out a variable that holds a line of text. You may recognize "/me" as a Snak command, but this line just puts together a line of text that starts with the "/me" command. The line is stored in a variable called "commandstring".

"do commandstring"

Finally we get to do an actual AppleScript command. We have a potential point of confusion here because we are mixing two different kinds of commands. There are normal Snak commands like you type in at the command line like "/me", and then there are Snak AppleScript commands like "do". The "do" Snak AppleScript command makes Snak execute a normal command as if you typed it in through the command line.

That means that you have access to all the built in Snak commands as well as any commands you define in the existing ircII language, from within an AppleScript.

So the "do commandstring" line simply executes the "/me sees ..." command as if you had typed it in yourself, which result in the ratio of ops to normal users being written out and sent as an action message to the channel.

How to load and run AppleScripts
In order to use an AppleScript it needs to be loaded into Snak. Type "/load scriptname" to make Snak read in and prepare the script to be run. If you have a handler in the script called "on load" it will be called right away. Snak will also look for a handler called "on idle" and start executing it if it is present.

If you type the name of the script as a command, the "on run" handler in the script will be run. At this time it is not possible to pass parameters to an AppleScript command, so you are encouraged to use the ircII language to write command aliases. This shortcoming will be remedied.

During development of an AppleScript it is frequently useful to unload an existing script in order to modify it and try again. To unload an a loaded AppleScript type "/unload scriptname".

Snak implements a number of event handlers that enable you to implement extensive functionality and the number of handlers will be improved in the next version. I welcome your feedback and suggestions so be sure to let me know if you need a particular feature.

Event Handlers
The real power of the AppleScript support comes into play when you wish to modify how Snak does particular things.

Example: If you are an IRC server operator you will get a number of messages from the network itself about the various going ons. This may become annoying if the messages are of no relevance to you. 

With AppleScript you now have a way to intercept those messages and process or discard them without cluttering up the channels you are in.

Snak will, during its processing of the numerous different events, call some user-defined "hook functions" or event handlers. Depending on the output of these event handlers, Snak may or may not continue processing the event. This means that the user now has the ability to tailor Snak much more closely to his or her needs than ever before.

Snak comes with the script file SnakEventHandlers which contains examples of all the event handlers that Snak currently supports, and shows what parameters they require.

The following example employs an event handler called "on servernotice". Snak will call the servernotice handler whenever it receives a notice from a server as opposed to a normal user. The example script will then examine the text of the notice and if it contains the string [CLONES] the message will be redirected to a custom window in order not to clutter up the regular channel.

Notice how the return value of the handler in the case of a [CLONES] message is true. This means that the script has completely processed the event and Snak should not process it as well.

on servernotice(con, source, sourcehost, target, thestring)

set eventhandled to false

tell application "Snak 4.6"

try

--if thestring contains "clones" then

tell connection con

echo thestring in filter "[CLONES]"

end tell

-- true tells Snak that this event is completely handled

set eventhandled to true

--end if

end try

end tell

return eventhandled
end servernotice

on load()

tell application "Snak 4.6"

set con to currentconnection

tell connection con

type "/window new name [CLONES]"

echo "Clone catcher" in filter "[CLONES]"

end tell

end tell
end load

The script uses the custom windows feature of Snak. The line "type "/window new name [CLONES]" will open a custom window that you can use to display text that is filtered out of somewhere else. Such windows are called filter windows.

Stacked Event Handlers
Snak allows you to have multiple AppleScripts loaded and each of the scripts can implement whatever event handlers it wants. Snak will then call each event handler in turn until one of them returns true, meaning that the event was completely processed.

Snak comes with some sample event handler scripts that illustrate this. If you examine the input1 and input2 scripts in the script folder you will see that they both have an on input handler. If you load them with "/load input1" and "/load input2" and type the text that triggers the action, you will see that both handlers are called.

Likewise, idle handlers can be stacked. The idle1 and idle2 scripts both contain idle handlers and if you load them with "/load idle1" and "/load idle2" you will see periodic messages coming from both of them.

This support for stacked handlers will eliminate much complexity from large script packages.